package com.study.transaction.dispatch.api;

import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import com.study.transaction.dispatch.service.DispatchService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import java.sql.SQLTimeoutException;

/**
 * @author: chenhs
 * @date: Created in 14:35 2019/12/17
 **/
@Component
public class OrderDispatchConsumer {

    private final Logger logger = LoggerFactory.getLogger(OrderDispatchConsumer.class);

    @Autowired
    DispatchService dispatchService;


    /**
     * spring集成，有数据时方法自动触发
     *
     * @param message
     * @param channel
     * @param tag
     */
    @RabbitListener(queues = "orderQueue")
    public void messageConsumer(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws Exception {

        try {
            //mq里面的数据转为json对象 --- 和发送者保持一致
            JSONObject orderInfo = JSONObject.parseObject(message);
            logger.warn("收到MQ里面的消息：" + orderInfo.toJSONString());
            //收到新订单
            Thread.sleep(5000L);

            /**
             * 去重
             * 发送可能重复，消费的时候如何处理？幂等性/去重
             * 创建一条运单（最终一致了） --- 结合业务设计进行去重
             */
            String orderId = orderInfo.getString("orderId");
            dispatchService.dispatch(orderId);
            //正确告诉MQ -- 正确处理完毕
            channel.basicAck(tag, false);
        } catch (DuplicateKeyException e){
            //@2020-05-19 去重的其中一种方案
            channel.basicAck(tag, false);
        }catch (SQLTimeoutException e) {
            //如果异常，重发；
            channel.basicNack(tag, false, true);
        } catch (Exception e) {
            //如果异常，不能够处理 -- 系统监控预警，人工干预
            //丢弃不要了，死信
            channel.basicNack(tag, false, false);
        }

        //如果不给回复，就等这个consumer断开链接后，mq-server会继续推送
    }


}
